package cn.iocoder.yudao.module.mzt.service.portal;

import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
import cn.iocoder.yudao.module.mzt.controller.admin.article.vo.ArticlePageReqVO;
import cn.iocoder.yudao.module.mzt.controller.app.portal.vo.*;
import cn.iocoder.yudao.module.mzt.dal.dataobject.article.ArticleDO;
import cn.iocoder.yudao.module.mzt.dal.dataobject.articletag.ArticleTagDO;
import cn.iocoder.yudao.module.mzt.dal.dataobject.category.CategoryDO;
import cn.iocoder.yudao.module.mzt.dal.dataobject.systemconfig.SystemConfigDO;
import cn.iocoder.yudao.module.mzt.dal.dataobject.tag.TagDO;
import cn.iocoder.yudao.module.mzt.dal.mysql.article.ArticleMapper;
import cn.iocoder.yudao.module.mzt.dal.mysql.articletag.ArticleTagMapper;
import cn.iocoder.yudao.module.mzt.dal.mysql.category.CategoryMapper;
import cn.iocoder.yudao.module.mzt.dal.mysql.systemconfig.SystemConfigMapper;
import cn.iocoder.yudao.module.mzt.dal.mysql.tag.TagMapper;
import cn.iocoder.yudao.module.system.api.user.AdminUserApi;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import jakarta.annotation.Resource;
import org.springframework.stereotype.Service;
import org.springframework.validation.annotation.Validated;

import java.util.*;
import java.util.stream.Collectors;

import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
import static cn.iocoder.yudao.module.mzt.enums.ErrorCodeConstants.ARTICLE_NOT_EXISTS;

/**
 * 首页数据 Service 实现类
 *
 * @author Geordie
 */
@Service
@Validated
public class PortalServiceImpl implements PortalService {
    @Resource
    private SystemConfigMapper systemConfigMapper;
    @Resource
    private ArticleMapper articleMapper;
    @Resource
    private CategoryMapper categoryMapper;
    @Resource
    private TagMapper tagMapper;
    @Resource
    private ArticleTagMapper articleTagMapper;
    @Resource
    private AdminUserApi adminUserApi;

    @Override
    public List<PortalConfigRespVO> getSystemConfig() {
        List<SystemConfigDO> configDOS = systemConfigMapper.selectList(new LambdaQueryWrapperX<SystemConfigDO>()
                .eqIfPresent(SystemConfigDO::getStatus, 0));
        return BeanUtils.toBean(configDOS, PortalConfigRespVO.class);
    }

    @Override
    public PageResult<ArticleDO> getArticlePage(ArticlePageReqVO pageReqVO) {
        Long count = 0L;
        if (pageReqVO.getTagId() != null && pageReqVO.getTagId() != 0) {
            Set<Long> collect = articleTagMapper.selectList(
                    new LambdaQueryWrapperX<ArticleTagDO>()
                            .eqIfPresent(ArticleTagDO::getTagId, pageReqVO.getTagId())
            ).stream().map(ArticleTagDO::getArticleId).collect(Collectors.toSet());
            if (!collect.isEmpty()) {
                count = articleMapper.selectCount(new LambdaQueryWrapperX<ArticleDO>()
                        .in(ArticleDO::getId, collect)
                        .likeIfPresent(ArticleDO::getTitle, pageReqVO.getTitle())
                        .likeIfPresent(ArticleDO::getSummary, pageReqVO.getSummary())
                        .eqIfPresent(ArticleDO::getStatus, pageReqVO.getStatus())
                        .eqIfPresent(ArticleDO::getRecommend, pageReqVO.getRecommend())
                        .likeIfPresent(ArticleDO::getSeoTitle, pageReqVO.getSeoTitle())
                        .likeIfPresent(ArticleDO::getSeoKeywords, pageReqVO.getSeoKeywords())
                        .likeIfPresent(ArticleDO::getSeoDescription, pageReqVO.getSeoDescription())
                        .betweenIfPresent(ArticleDO::getCreateTime, pageReqVO.getCreateTime())
                        .likeIfPresent(ArticleDO::getCategoryName, pageReqVO.getCategoryName()));
            }

        } else {
            // 查询总数
            count = articleMapper.selectCount(new LambdaQueryWrapperX<ArticleDO>()
                    .likeIfPresent(ArticleDO::getTitle, pageReqVO.getTitle())
                    .likeIfPresent(ArticleDO::getSummary, pageReqVO.getSummary())
                    .eqIfPresent(ArticleDO::getStatus, pageReqVO.getStatus())
                    .eqIfPresent(ArticleDO::getRecommend, pageReqVO.getRecommend())
                    .likeIfPresent(ArticleDO::getSeoTitle, pageReqVO.getSeoTitle())
                    .likeIfPresent(ArticleDO::getSeoKeywords, pageReqVO.getSeoKeywords())
                    .likeIfPresent(ArticleDO::getSeoDescription, pageReqVO.getSeoDescription())
                    .betweenIfPresent(ArticleDO::getCreateTime, pageReqVO.getCreateTime())
                    .likeIfPresent(ArticleDO::getCategoryName, pageReqVO.getCategoryName()));
        }

        // 如果总数为 0,直接返回空
        if (count == 0) {
            return new PageResult<>(Collections.emptyList(), count);
        }
        // 实际分页查询
        List<ArticleDO> list = articleMapper.selectPageWithRelations(pageReqVO);
        Set<Long> allTagIds = list.stream()
                .filter(article -> article.getTagIds() != null)
                .flatMap(aDo -> aDo.getTagIds().stream())
                .collect(Collectors.toSet());
        if (!allTagIds.isEmpty()) {
            // 查询所有标签
            List<TagDO> tagDOS = tagMapper.selectByIds(new ArrayList<>(allTagIds));
            Map<Long, String> tagIdToNameMap = tagDOS.stream()
                    .collect(Collectors.toMap(TagDO::getId, TagDO::getName));
            for (ArticleDO aDo : list) {
                if (aDo.getTagIds() != null && aDo.getTagIds().size() > 0) {
                    List<String> tagNames = aDo.getTagIds().stream()
                            .map(tagIdToNameMap::get)
                            .filter(Objects::nonNull) // 过滤掉未找到的标签
                            .collect(Collectors.toList());
                    aDo.setTagNames(tagNames);
                }
            }
        }
        return new PageResult<>(list, count);
    }

    @Override
    public List<ArticleDO> inquireArticle(Long categoryId,Long tagId, String keywords) {
        List<ArticleDO> list = articleMapper.inquireArticle(categoryId,tagId,keywords);
        Set<Long> allTagIds = list.stream()
                .filter(article -> article.getTagIds() != null)
                .flatMap(aDo -> aDo.getTagIds().stream())
                .collect(Collectors.toSet());
        if (!allTagIds.isEmpty()) {
            // 查询所有标签
            List<TagDO> tagDOS = tagMapper.selectByIds(new ArrayList<>(allTagIds));
            Map<Long, String> tagIdToNameMap = tagDOS.stream()
                    .collect(Collectors.toMap(TagDO::getId, TagDO::getName));
            for (ArticleDO aDo : list) {
                if (aDo.getTagIds() != null && aDo.getTagIds().size()> 0) {
                    List<String> tagNames = aDo.getTagIds().stream()
                            .map(tagIdToNameMap::get)
                            .filter(Objects::nonNull) // 过滤掉未找到的标签
                            .collect(Collectors.toList());
                    aDo.setTagNames(tagNames);
                }
            }
        }
        return list;
    }

    @Override
    public PortalArticleRespVO getArticleById(Long id) {
        // 根据 ID 查询文章
        ArticleDO article = articleMapper.selectWithRelations(id);
        if (article == null) {
            throw exception(ARTICLE_NOT_EXISTS);
        }
        // 处理标签信息
        List<Long> tagIds = article.getTagIds();
        if (tagIds != null && !tagIds.isEmpty()) {
            List<TagDO> tagDOS = tagMapper.selectByIds(tagIds);
            List<Long> tagIdList = tagDOS.stream().map(TagDO::getId).collect(Collectors.toList());
            List<String> tagNameList = tagDOS.stream().map(TagDO::getName).collect(Collectors.toList());
            article.setTagIds(tagIdList);
            article.setTagNames(tagNameList);
        }
        // 转换为响应对象
        PortalArticleRespVO response = BeanUtils.toBean(article, PortalArticleRespVO.class);
        // 设置用户信息
        response.setUserInfo(adminUserApi.getUser(Long.parseLong(article.getCreator())));
        // 查询上一篇和下一篇文章
        setNeighborArticles(response, article.getCategoryId(), id);
        return response;
    }

    private void setNeighborArticles(PortalArticleRespVO response, Long categoryId, Long currentId) {
        ArticleDO previousArticle = articleMapper.selectPreviousArticle(currentId, categoryId);
        response.setPreviousArticle(formatArticleNeighbor(previousArticle));

        ArticleDO nextArticle = articleMapper.selectNextArticle(currentId, categoryId);
        response.setNextArticle(formatArticleNeighbor(nextArticle));
    }

    private String formatArticleNeighbor(ArticleDO article) {
        return article == null ? null : article.getTitle() + "*X*X*" + article.getId();
    }

    @Override
    public List<PortalTagRespVO> getTagList() {
        List<TagDO> tagDOS = tagMapper.selectList(
                new LambdaQueryWrapperX<TagDO>()
                        .eqIfPresent(TagDO::getStatus, 0)
                        .orderByAsc(TagDO::getSort)
                        .last("LIMIT 8"));
        return BeanUtils.toBean(tagDOS, PortalTagRespVO.class);
    }

    @Override
    public List<PortalRecommendArticleRespVO> getRecommendArticleList() {
        // 查询所有符合条件的分类
        List<CategoryDO> categoryDOS = categoryMapper.selectList(new LambdaQueryWrapperX<CategoryDO>()
                .eq(CategoryDO::getType, "TOP") // 只获取分类顶部菜单
                .eq(CategoryDO::getStatus, 0)
                .eq(CategoryDO::getRecommend, 0)
                        .eq(CategoryDO::getLevel, 3)
                .orderByAsc(CategoryDO::getSort));

        // 获取所有分类的 ID
        List<Long> categoryIds = categoryDOS.stream()
                .map(CategoryDO::getId)
                .collect(Collectors.toList());

        // 查询所有符合条件的文章，使用 categoryIds 进行过滤
        List<ArticleDO> articles = articleMapper.selectList(new LambdaQueryWrapperX<ArticleDO>()
                .eqIfPresent(ArticleDO::getStatus, 0)
                .eqIfPresent(ArticleDO::getRecommend, 0)
                .inIfPresent(ArticleDO::getCategoryId, categoryIds)
                .orderByDesc(ArticleDO::getCreateTime));

        // 将 ArticleDO 转换为 Map，以便快速查找
        Map<Long, List<ArticleDO>> articlesByCategoryId = articles.stream()
                .collect(Collectors.groupingBy(ArticleDO::getCategoryId));

        // 限制每个分类最多 6 个文章
        Map<Long, List<ArticleDO>> limitedArticlesByCategoryId = articlesByCategoryId.entrySet().stream()
                .collect(Collectors.toMap(
                        Map.Entry::getKey,
                        entry -> entry.getValue().stream().limit(6).collect(Collectors.toList())
                ));

        // 转换 CategoryDO 为 PortalRecommendArticleRespVO，并设置文章列表
        return categoryDOS.stream()
                .map(category -> {
                    PortalRecommendArticleRespVO response = BeanUtils.toBean(category, PortalRecommendArticleRespVO.class);
                    response.setArticleList(limitedArticlesByCategoryId.getOrDefault(category.getId(), Collections.emptyList()));
                    return response;
                })
                .collect(Collectors.toList());
    }

    @Override
    public PortalRecommendArticleRespVO getCategoryById(PortalPageReqVO reqVO) {
        // 获取分类信息
        PortalRecommendArticleRespVO portalRecommendArticleRespVO = BeanUtils.toBean(
                categoryMapper.selectById(reqVO.getCategoryId()),
                PortalRecommendArticleRespVO.class
        );
        if (portalRecommendArticleRespVO != null) {
            // 创建分页对象
            Page<ArticleDO> page = new Page<>(reqVO.getPageNo(), reqVO.getPageSize());
            // 执行分页查询
            IPage<ArticleDO> articlePage = articleMapper.selectPage(
                    page,
                    new LambdaQueryWrapperX<ArticleDO>()
                            .eqIfPresent(ArticleDO::getCategoryId, reqVO.getCategoryId())
                            .eqIfPresent(ArticleDO::getStatus, 0)
                            .orderByDesc(ArticleDO::getCreateTime)
            );
            // 设置文章列表和总数
            portalRecommendArticleRespVO.setArticleList(articlePage.getRecords());
            portalRecommendArticleRespVO.setTotal(articlePage.getTotal());
        }
        return portalRecommendArticleRespVO;
    }

    @Override
    public PortalDataObjectRespVO getDataObject(Long categoryId) {
        PortalDataObjectRespVO response = new PortalDataObjectRespVO();
        response.setRecommendArticles(articleMapper.selectList(new LambdaQueryWrapperX<ArticleDO>()
                        .eqIfPresent(ArticleDO::getRecommend, 0)
                        .orderByDesc(ArticleDO::getCreateTime)
                        .last("LIMIT 6")))
                .setRecentArticles(articleMapper.selectList(new LambdaQueryWrapperX<ArticleDO>()
                        .orderByDesc(ArticleDO::getCreateTime)
                        .last("LIMIT 6")))
                .setRankingArticles(articleMapper.selectList(new LambdaQueryWrapperX<ArticleDO>()
                        .orderByAsc(ArticleDO::getViewCount)
                        .last("LIMIT 6")))
                .setCorrelationRecommendArticles(articleMapper.selectList(new LambdaQueryWrapperX<ArticleDO>()
                        .eqIfPresent(ArticleDO::getCategoryId, categoryId)
                        .orderByDesc(ArticleDO::getCreateTime)
                        .last("LIMIT 6")));
        return response;
    }

    @Override
    public PortalCategoryRespVO getCategoryList() {
        // 从数据库获取分类列表，并过滤出状态为 0 的数据
        List<CategoryDO> selectList = categoryMapper.selectList(new LambdaQueryWrapperX<CategoryDO>()
                .eqIfPresent(CategoryDO::getStatus, 0)
                .orderByAsc(CategoryDO::getSort));
        // 创建一个响应对象
        PortalCategoryRespVO portalCategoryRespVO = new PortalCategoryRespVO();
        // 初始化分类列表
        List<PortalCategoryRespVO.Category> topCategories = new ArrayList<>();
        List<PortalCategoryRespVO.Category> middleCategories = new ArrayList<>();
        List<PortalCategoryRespVO.Category> rightCategories = new ArrayList<>();
        // 将初始化的列表放入 Map
        Map<String, List<PortalCategoryRespVO.Category>> categoryMap = new HashMap<>();
        categoryMap.put("TOP", topCategories);
        categoryMap.put("MIDDLE", middleCategories);
        categoryMap.put("RIGHT", rightCategories);
        // 遍历选择的分类列表，将分类添加到对应的集合中
        for (CategoryDO aDo : selectList) {
            // 将一行分类转换为 VO 类型
            PortalCategoryRespVO.Category category = BeanUtils.toBean(aDo, PortalCategoryRespVO.Category.class);
            // 获取对应类型的列表并添加
            List<PortalCategoryRespVO.Category> categoryList = categoryMap.get(aDo.getType());
            if (categoryList != null) {
                categoryList.add(category);
            }
        }
        // 将分类列表设置到 portalCategoryRespVO 中
        portalCategoryRespVO.setTopCategory(topCategories);
        portalCategoryRespVO.setMiddleCategory(middleCategories);
        portalCategoryRespVO.setRightCategory(rightCategories);
        return portalCategoryRespVO;
    }
}
